package org.summerframework.core.context;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.summerframework.core.xml.SummerXmlParser;
import org.summerframework.core.xml.WaitInitializedBean;
import org.summerframework.core.xml.WaitInitializedBean.Dependence;

/**
 * 类路径xml上下文
 *
 * @author sumou
 * @date 2025/02/19
 */
public class ClassPathXmlApplicationContext implements ApplicationContext {

    /**
     * Bean容器
     */
    private final Map<String, Object> beanContext = new HashMap<>();

    public ClassPathXmlApplicationContext(String configLocation) {
        // 解析xml中等待被初始化的Bean
        SummerXmlParser parser = new SummerXmlParser();
        InputStream stream = getClass().getClassLoader().getResourceAsStream(configLocation);
        WaitInitializedBean waitInitializedBean = parser.parseXml(stream);
        Map<String, String> beanMap = waitInitializedBean.getBeanMap();
        List<Dependence> depList = waitInitializedBean.getDepList();
        // 利用反射机制初始化所有Bean
        beanMap.forEach((key, value) -> {
            try {
                Class<?> clazz = Class.forName(value);
                Constructor<?> constructor = clazz.getDeclaredConstructor();
                constructor.setAccessible(true);
                Object object = constructor.newInstance();
                beanContext.put(key, object);
            } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |
                     InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        });
        // 依赖注入
        depList.forEach(dep -> {
            // 获取部分数值
            String beanId = dep.getBeanId();
            Object object = beanContext.get(beanId);
            String setterMethodName = dep.getName();
            String ref = dep.getRef();
            Object refObject = beanContext.get(ref);
            // 构建
            Class<?> clazz = object.getClass();
            try {
                Method method = clazz.getDeclaredMethod("set" + capitalizeFirstLetter(setterMethodName),
                    refObject.getClass());
                method.setAccessible(true);
                method.invoke(object, refObject);
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        });
    }

    private static String capitalizeFirstLetter(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    @Override
    public Object getBean(String name) {
        return beanContext.get(name);
    }

}
